package ar.fi.uba.celdas.correccion.prediccion.heuristicas;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import ar.fi.uba.celdas.correccion.prediccion.HeuristicaPrediccion;
import ar.fi.uba.celdas.interfaces.bc.IBaseConocimientos;
import ar.fi.uba.celdas.interfaces.bc.Regla;
import ar.fi.uba.celdas.interfaces.bc.Sensor;

public class Culpabilidad extends HeuristicaPrediccion {
	
	@Override
	public void corregirRegla(Regla original, IBaseConocimientos bc) {
		
		Collection<Sensor> condicionesTeoria = new ArrayList<Sensor>(original.getCondiciones());
		//actualmente agregar las negadas de la regla elegida esta de más ya que el robot no informa condiciones negadas y por ende
		//no tendriamos nunca una condicion de este tipo dentro de las posibles culpables. En futuras implementaciones se podría necesitar
		condicionesTeoria.addAll(original.getCondicionesNegadas()); 
		
		Collection<Sensor> condicionesCulpables = new ArrayList<Sensor>(bc.getEstadoAnterior());
		
		for(Sensor condicionTeoria : condicionesTeoria){
			//se culpa a las condiciones que no se encuentran en las condiciones de la Teoria (las condiciones que vienen en la regla original)
			condicionesCulpables.remove(condicionTeoria);
		}		
		
		Collection<Sensor> culpables = new ArrayList<Sensor>();
		Map<Sensor, Integer> cantidadFallos = this.getSumaFallosByCondicion(condicionesCulpables, bc);
		
		//Nos quedamos con la condicion o las condiciones que tengan mayor cantidad de fallos (mas culpables)
		if (!cantidadFallos.isEmpty()) {
			int culpabilidadMax = 0;
			for(Sensor condicionCulpable : condicionesCulpables){
				if (cantidadFallos.containsKey(condicionCulpable)) {
					int culpabilidadAux = cantidadFallos.get(condicionCulpable);
					if(culpabilidadAux >= culpabilidadMax){
						 if(culpabilidadAux > culpabilidadMax){
							 //se encontro una más culpable, se eliminan las anteriores
							 culpabilidadMax = culpabilidadAux;
							 culpables.clear();
						 }
						culpables.add(condicionCulpable);
					}
				}
			}	
		} else {
			//si no hay registro de fallos, se agregan todas la condiciones que podrian ser culpables
			culpables.addAll(condicionesCulpables);
		}
		
		if(!culpables.isEmpty()){
			this.actualizar(original, culpables, bc);			
		}
		System.out.println("Regla corregida utilizando la Heuristica de Culpabilidad");	
		
	}
	
	
	/**
	 * @return Map con la suma de fallos de todas las teorias donde se encuentre cada condicion
	 **/
	private Map<Sensor, Integer> getSumaFallosByCondicion(Collection<Sensor> condiciones, IBaseConocimientos bc){
		Map<Sensor, Integer> cantidades = new HashMap<Sensor, Integer>();
		for(Regla regla : bc.getReglas()){			
			for(Sensor condicion : condiciones){
				//No se busca en CondicionesNegadas ya que el sensor solo informa las positivas
				if(regla.getCondiciones().contains(condicion)){
					int fallosRegla = regla.getUso() - regla.getExitos();
					Integer sumaFallos = cantidades.get(condicion);
					if(sumaFallos == null){
						sumaFallos = fallosRegla;
					}else{
						sumaFallos += fallosRegla;
					}
					cantidades.put(condicion, sumaFallos);
				}
			}
		}
		return cantidades;
	}
	
}
